package csci6450.chickenFriedFS.nuggetServer;

import csci6450.chickenFriedFS.nuggetCore.NuggetServerInfo;
import csci6450.chickenFriedFS.nuggetServer.threads.NuggetServerClientListener;
import csci6450.chickenFriedFS.nuggetServer.threads.NuggetServerMetaListener;
import csci6450.chickenFriedFS.nuggetServer.threads.NuggetServerReplicationListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ServerSocketFactory;

/**
 *  <p style="margin-top: 0">
 *        Nugget Server models the file system's object server(s).
 *      </p>
 */
// <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
// #[regen=yes,id=DCE.C7F3D213-5584-BAEF-FFB8-568899A535C0]
// </editor-fold> 
public class NuggetServer {

    public final int STARTING_PORT = 3000;
    private int identifierNum;
    private String identifierPrefix;
    private String metaServerLocation;
    private NuggetServerClientListener clientListener;
    private NuggetServerMetaListener metaListner;
    private static NuggetServer nuggetServer;
    private NuggetServerReplicationListener repListener;

    static {
        try {
            nuggetServer = new NuggetServer();
        } catch (IOException ex) {
            Logger.getLogger(NuggetServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.9A52CD80-FF80-7957-973B-2DCC8E66F0BD]
    // </editor-fold> 
    private NuggetServer() throws IOException {
        NuggetFileStoreManager.getInstance().loadExistingNuggets(NuggetServerLog.getInstance().getNuggetList());
        if (!this.registerWithMetaServer()) {
            System.out.println("Unable to register with the Meta server at " + RuntimeSettings.getInstance().getMetaServerIp() + ":" + RuntimeSettings.getInstance().getMetaServerPort());
            System.exit(0);
        }
        this.clientListener = new NuggetServerClientListener();
        this.metaListner = new NuggetServerMetaListener();
        this.repListener = new NuggetServerReplicationListener();
    }

    public static NuggetServer getInstance() {
        return nuggetServer;
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.CB1B9D42-1B29-D0B4-57E0-87A72990192B]
    // </editor-fold> 
    public void start() throws FileNotFoundException, IOException {
        this.clientListener.start();
        this.metaListner.start();
        this.repListener.start();
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.53E70E11-012D-6FA3-4385-AFF8500E9BAE]
    // </editor-fold> 
    public void stop() {
        System.exit(0);
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,regenBody=yes,id=DCE.50D206AF-CFA6-B64C-FCD2-E1047506B4D4]
    // </editor-fold> 
    public int getIdentifierNum() {
        return identifierNum;
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,regenBody=yes,id=DCE.118827FC-2F8A-4536-00E6-8BD622B5A9BB]
    // </editor-fold> 
    public void setIdentifierNum(int val) {
        this.identifierNum = val;
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,regenBody=yes,id=DCE.C1BFA083-109D-DAEB-5C55-1A30D8247868]
    // </editor-fold> 
    public String getIdentifierPrefix() {
        return identifierPrefix;
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,regenBody=yes,id=DCE.D553ACDE-7B80-DF60-6F48-6C1001C75D19]
    // </editor-fold> 
    public void setIdentifierPrefix(String val) {
        this.identifierPrefix = val;
    }

    /**
     *  <p style="margin-top: 0">
     *        Increments identiferNum.  Returns identifierPrefix + (String) 
     *        identifierNum
     *      </p>
     */
    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.E8EB4DFC-3B5A-4C4F-519D-C00F9AE1D2B9]
    // </editor-fold> 
    public String getNextIdentifier() {
        return null;
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,regenBody=yes,id=DCE.749AAB26-6C3E-B2BC-4B95-A7031E5BA30C]
    // </editor-fold> 
    public String getMetaServerLocation() {
        return metaServerLocation;
    }

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,regenBody=yes,id=DCE.5DD5D885-348C-0E9D-8F29-4E78D25364E5]
    // </editor-fold> 
    public void setMetaServerLocation(String val) {
        this.metaServerLocation = val;
    }

    public boolean registerWithMetaServer() {

        boolean success = false;
        Socket socket = null;
        try {
            socket = new Socket(RuntimeSettings.getInstance().getMetaServerIp(), RuntimeSettings.getInstance().getMetaServerPort());
            ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
            ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
            NuggetServerInfo info = new NuggetServerInfo(new Date(),
                    NuggetFileStoreManager.getInstance().getNumberOfAvalaibleNuggets(),
                    InetAddress.getLocalHost().getHostAddress(),
                    RuntimeSettings.getInstance().getClientListenerPort(),
                    RuntimeSettings.getInstance().getMetaListenerPort(),
                    NuggetServerLog.getInstance().getLatestNuggets(),
                    RuntimeSettings.getInstance().getNumberOfChunks(),
                    RuntimeSettings.getInstance().getReplicationPort());
            outputStream.writeObject(info);
            outputStream.flush();
            //should be a port number that the server will be listening on to receive
            //the file
            String serverResponse = (String) inputStream.readObject();
            if (serverResponse.equals("Success")) {
                success = true;
            } else {
                success = false;
            }
        } catch (IOException ex) {
            success = false;
        } catch (ClassNotFoundException ex) {
            success = false;
        } finally {
            try {
                if (socket != null) {
                    socket.close();
                }
            } catch (IOException ex) {
            }
        }
        return success;
    }
}

